// 嵌入的代码
%{
package main

import (
    "fmt"
    "text/scanner"
    "os"
    "strings"
    "strconv"
)

// 定义语法树节点
type Expr interface{}

type Token struct {
    token int
    literal string
}

type NumExpr struct {
    literal string
}

type BinOpExpr struct {
    left Expr
    right Expr
    operator rune
}

type Lexer struct {
    scanner.Scanner
    result Expr
}

/* 需要实现
type yyLexer interface {
    Lex(lval *yySymType) int
    Error(s string)
}
*/
%}

%union{
    token Token
    expr  Expr
}

// 语法定义
%type <expr> program
%type <expr> expr

%token <token> NUMBER

%left '+' '-'
%left '*' '/'

%%

// 程序对应表达
program: expr {
    $$ = $1
    yylex.(*Lexer).result = $$
}

expr: NUMBER {
    $$ = NumExpr{literal: $1.literal}
} | expr '+' expr {
    $$ = BinOpExpr{left: $1, operator: '+', right: $3}
} | expr '-' expr {
    $$ = BinOpExpr{left: $1, operator: '-', right: $3}
} | expr '*' expr {
    $$ = BinOpExpr{left: $1, operator: '*', right: $3}
} | expr '/' expr {
    $$ = BinOpExpr{left: $1, operator: '/', right: $3}
}

%%

func (l *Lexer) Lex(lval *yySymType) int {
    token := int(l.Scan())
    if token == scanner.Int {
        token = NUMBER
    }
    lval.token = Token{token: token, literal: l.TokenText()}
    return token
}

func (l *Lexer) Error(e string) {
    panic(e)
}



// 可以在这里写，也可以在上面写
// 词法分析器
func Eval(e Expr) int {
    switch e.(type) {
    case BinOpExpr:
        left := Eval(e.(BinOpExpr).left)
        right := Eval(e.(BinOpExpr).right)

        switch e.(BinOpExpr).operator {
        case '+':
            return left + right
        case '-':
            return left - right
        case '*':
            return left * right
        case '/':
            return left / right
        }
    case NumExpr:
        num, _ := strconv.Atoi(e.(NumExpr).literal)
        return num
    }
    return 0
}

func main() {
    l := new(Lexer)
    l.Init(strings.NewReader(os.Args[1]))
    yyParse(l)
    fmt.Printf("%d\n", Eval(l.result))
}